#include "UnityPBSLighting.cginc"
#include "AutoLight.cginc"
#include "UnityCG.cginc"

struct VertexInput
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    float3 normal : NORMAL;
    float4 tangent : TANGENT;
    float4 color : COLOR;
};

struct VertexOutput
{	
    #if defined(Geometry)
        float4 pos : CLIP_POS;
        float4 vertex : SV_POSITION; 
    #else
        float4 pos : SV_POSITION;
    #endif

    float2 uv : TEXCOORD0;
    float3 ntb[3] : TEXCOORD2; //texcoord 3, 4 || Holds World Normal, Tangent, and Bitangent
    float4 worldPos : TEXCOORD5;
    float4 color : TEXCOORD6;
    float3 normal : TEXCOORD8;
    float4 screenPos : TEXCOORD9;
    float3 objPos : TEXCOORD11;

    SHADOW_COORDS(7)
    UNITY_FOG_COORDS(10)
};

#if defined(Geometry)
    struct v2g
    {
        float4 pos : CLIP_POS;
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0; 
        float3 ntb[3] : TEXCOORD2; //texcoord 3, 4 || Holds World Normal, Tangent, and Bitangent
        float4 worldPos : TEXCOORD5;
        float4 color : TEXCOORD6;
        float3 normal : TEXCOORD8;
        float4 screenPos : TEXCOORD9;
        float3 objPos : TEXCOORD11;

        SHADOW_COORDS(7)
        UNITY_FOG_COORDS(10)
    };

    struct g2f
    {
        float4 pos : SV_POSITION;
        float2 uv : TEXCOORD0;
        float3 ntb[3] : TEXCOORD2; //texcoord 3, 4 || Holds World Normal, Tangent, and Bitangent
        float4 worldPos : TEXCOORD5;
        float4 color : TEXCOORD6;
        float4 screenPos : TEXCOORD8;
        float3 objPos : TEXCOORD10;

        SHADOW_COORDS(7)
        UNITY_FOG_COORDS(9)
    };
#endif

struct CustomLighting
{
    half4 albedo;
    half4 normalMap;
    half4 metallicGlossMap;
    half4 specularMap;
    half4 occlusion;
    half4 emissionMap;

    half3 diffuseColor;
    half attenuation;
    half3 normal;
    half3 tangent;
    half3 bitangent;
    half4 worldPos;
    half3 color;
    float isOutline;
    float2 screenUV;
    float3 objPos;
};

struct TextureUV
{	
    half2 uv0;
    half2 albedoUV;
    half2 specularMapUV;
    half2 metallicGlossMapUV;
    half2 normalMapUV;
    half2 occlusionUV;
    half2 emissionMapUV;
};

struct DotProducts
{
    half ndl;
    half vdn;
    half vdh;
    half tdh;
    half bdh;
    half ndh;
    half rdv;
    half ldh;
    half svdn;
};

UNITY_DECLARE_TEX2D(_MainTex); half4 _MainTex_ST;
UNITY_DECLARE_TEX2D_NOSAMPLER(_BumpMap); half4 _BumpMap_ST;
UNITY_DECLARE_TEX2D_NOSAMPLER(_SpecularMap); half4 _SpecularMap_ST;
UNITY_DECLARE_TEX2D_NOSAMPLER(_MetallicGlossMap); half4 _MetallicGlossMap_ST;
UNITY_DECLARE_TEX2D_NOSAMPLER(_EmissionMap); half4 _EmissionMap_ST;
sampler2D _OcclusionMap; half4 _OcclusionMap_ST;
samplerCUBE _BakedCubemap;

half4 _Color,_OutlineColor, _OcclusionColor,_EmissionColor, _RimColor;

half _Metallic, _Glossiness;
half _SpecularIntensity, _SpecularArea;
half _RimRange, _RimIntensity;
half _ShadowSharpness;
half _OutlineWidth;

int _UVSetAlbedo, _UVSetNormal, _UVSetMetallic, _UVSetSpecular, _UVSetOcclusion, _UVSetEmission;
      
//Defines for helper functions
#define grayscaleVec float3(0.2125, 0.7154, 0.0721)

//HelperFunctions
void calcNormal(inout CustomLighting i)
{
    
    half3 nMap = UnpackScaleNormal(i.normalMap, 1);
    
    half3 tspace0 = half3(i.tangent.x, i.bitangent.x, i.normal.x);
    half3 tspace1 = half3(i.tangent.y, i.bitangent.y, i.normal.y);
    half3 tspace2 = half3(i.tangent.z, i.bitangent.z, i.normal.z);

    half3 calcedNormal;
    calcedNormal.x = dot(tspace0, nMap);
    calcedNormal.y = dot(tspace1, nMap);
    calcedNormal.z = dot(tspace2, nMap);
    
    calcedNormal = normalize(calcedNormal);
    
    half3 bumpedTangent = (cross(i.bitangent, calcedNormal));
    half3 bumpedBitangent = (cross(calcedNormal, bumpedTangent));

    i.normal = calcedNormal;
    i.tangent = bumpedTangent;
    i.bitangent = bumpedBitangent;
}

void InitializeTextureUVs(
    #if defined(Geometry)
        in g2f i,
    #else
        in VertexOutput i, 
    #endif
        inout TextureUV t)
{	
    half2 uvSetNormalMap = i.uv;
    t.normalMapUV = TRANSFORM_TEX(uvSetNormalMap, _BumpMap);

    half2 uvSetEmissionMap = i.uv;
    t.emissionMapUV = TRANSFORM_TEX(uvSetEmissionMap, _EmissionMap);

    half2 uvSetMetallicGlossMap = i.uv;
    t.metallicGlossMapUV = TRANSFORM_TEX(uvSetMetallicGlossMap, _MetallicGlossMap);

    half2 uvSetOcclusion = i.uv;
    t.occlusionUV = TRANSFORM_TEX(uvSetOcclusion, _OcclusionMap);

    half2 uvSetAlbedo = i.uv;
    t.albedoUV = TRANSFORM_TEX(uvSetAlbedo, _MainTex);

    half2 uvSetSpecularMap = i.uv;
    t.specularMapUV = TRANSFORM_TEX(uvSetSpecularMap, _SpecularMap);
}

half2 calcScreenUVs(half4 screenPos)
{
    half2 uv = screenPos / (screenPos.w + 0.0000000001); 
    #if UNITY_SINGLE_PASS_STEREO
        uv.xy *= half2(_ScreenParams.x * 2, _ScreenParams.y);	
    #else
        uv.xy *= _ScreenParams.xy;
    #endif
    
    return uv;
}

half3 calcViewDir(half3 worldPos)
{
    half3 viewDir = _WorldSpaceCameraPos - worldPos;
    return normalize(viewDir);
}

half3 calcStereoViewDir(half3 worldPos)
{
    #if UNITY_SINGLE_PASS_STEREO
        half3 cameraPos = half3((unity_StereoWorldSpaceCameraPos[0]+ unity_StereoWorldSpaceCameraPos[1])*.5); 
    #else
        half3 cameraPos = _WorldSpaceCameraPos;
    #endif
        half3 viewDir = cameraPos - worldPos;
    return normalize(viewDir);
}
                     
half3 getReflectionUV(half3 direction, half3 position, half4 cubemapPosition, half3 boxMin, half3 boxMax) 
{
    #if UNITY_SPECCUBE_BOX_PROJECTION
        if (cubemapPosition.w > 0) {
            half3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction;
            half scalar = min(min(factors.x, factors.y), factors.z);
            direction = direction * scalar + (position - cubemapPosition);
        }
    #endif
    return direction;
}

half3 getEnvMap(CustomLighting i, DotProducts d, float blur, half3 reflDir, half3 indirectLight, half3 wnormal)
{
    half3 envMap = half3(0,0,0);

    #if defined(UNITY_PASS_FORWARDBASE) //Indirect PBR specular should only happen in the forward base pass. Otherwise each extra light adds another indirect sample, which could mean you're getting too much light. 
        half3 reflectionUV1 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
        half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, blur);
        half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR);

        half3 indirectSpecular;
        half interpolator = unity_SpecCube0_BoxMin.w;
        
        UNITY_BRANCH
        if (interpolator < 0.99999) 
        {
            half3 reflectionUV2 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
            half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, blur);
            half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR);
            indirectSpecular = lerp(probe1sample, probe0sample, interpolator);
        }
        else 
        {
            indirectSpecular = probe0sample;
        }

        envMap = indirectSpecular;
    #endif

    return envMap;
}



//Light Functions
  half3 calcReflView(half3 viewDir, half3 normal)
    {
        return reflect(-viewDir, normal);
    }
    
    half3 calcReflLight(half3 lightDir, half3 normal)
    {
        return reflect(lightDir, normal);
    }

half3 getVertexLightsDir(CustomLighting i, half4 vertexLightAtten)
{
    half3 toLightX = half3(unity_4LightPosX0.x, unity_4LightPosY0.x, unity_4LightPosZ0.x);
    half3 toLightY = half3(unity_4LightPosX0.y, unity_4LightPosY0.y, unity_4LightPosZ0.y);
    half3 toLightZ = half3(unity_4LightPosX0.z, unity_4LightPosY0.z, unity_4LightPosZ0.z);
    half3 toLightW = half3(unity_4LightPosX0.w, unity_4LightPosY0.w, unity_4LightPosZ0.w);

    half3 dirX = toLightX - i.worldPos;
    half3 dirY = toLightY - i.worldPos;
    half3 dirZ = toLightZ - i.worldPos;
    half3 dirW = toLightW - i.worldPos;
    
    dirX *= length(toLightX) * vertexLightAtten.x * unity_LightColor[0];
    dirY *= length(toLightY) * vertexLightAtten.y * unity_LightColor[1];
    dirZ *= length(toLightZ) * vertexLightAtten.z * unity_LightColor[2];
    dirW *= length(toLightW) * vertexLightAtten.w * unity_LightColor[3];

    half3 dir = (dirX + dirY + dirZ + dirW) / 4;
    return dir;
}

half3 calcLightDir(CustomLighting i, half4 vertexLightAtten)
{   
    half3 lightDir = UnityWorldSpaceLightDir(i.worldPos);

    half3 probeLightDir = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz;
    lightDir = (lightDir + probeLightDir); 
    
    #if defined(VERTEXLIGHT_ON)
        half3 vertexDir = getVertexLightsDir(i, vertexLightAtten);
        lightDir = (lightDir + probeLightDir + vertexDir);
    #endif

    #if !defined(POINT) && !defined(SPOT) && !defined(VERTEXLIGHT_ON) // if the average length of the light probes is null, and we don't have a directional light in the scene, fall back to our fallback lightDir
        if(length(unity_SHAr.xyz*unity_SHAr.w + unity_SHAg.xyz*unity_SHAg.w + unity_SHAb.xyz*unity_SHAb.w) == 0 && length(lightDir) < 0.1)
        {
            lightDir = half4(1, 1, 1, 0);
        }
    #endif

    return normalize(lightDir);
}

void calcLightCol(bool lightEnv, inout half3 indirectDiffuse, inout half4 lightColor)
{
    if(lightEnv)
    {
        lightColor = _LightColor0;
        indirectDiffuse = indirectDiffuse;
    }
    else
    {
        lightColor = indirectDiffuse.xyzz * 0.6;    
        indirectDiffuse = indirectDiffuse * 0.4;                                                    
    }
}

half3 get4VertexLightsColFalloff(half3 worldPos, half3 normal, inout half4 vertexLightAtten)
{
    half3 lightColor = 0;
    half4 toLightX = unity_4LightPosX0 - worldPos.x;
    half4 toLightY = unity_4LightPosY0 - worldPos.y;
    half4 toLightZ = unity_4LightPosZ0 - worldPos.z;

    half4 lengthSq = 0;
    lengthSq += toLightX * toLightX;
    lengthSq += toLightY * toLightY;
    lengthSq += toLightZ * toLightZ;

    float4 atten = 1.0 / (1.0 + lengthSq * unity_4LightAtten0);
    float4 atten2 = saturate(1 - (lengthSq * unity_4LightAtten0 / 25));
    atten = min(atten, atten2 * atten2);

    half4 colorFalloff = smoothstep(-0.7, 1.3, atten);
    vertexLightAtten = atten;

    half gs0 = dot(unity_LightColor[0], grayscaleVec);
    half gs1 = dot(unity_LightColor[1], grayscaleVec);
    half gs2 = dot(unity_LightColor[2], grayscaleVec);
    half gs3 = dot(unity_LightColor[3], grayscaleVec);

    lightColor.rgb += unity_LightColor[0]* atten.x; 
    lightColor.rgb += unity_LightColor[1]* atten.y; 
    lightColor.rgb += unity_LightColor[2]* atten.z; 
    lightColor.rgb += unity_LightColor[3]* atten.w; 

    return lightColor;
}

half4 calcMetallicSmoothness(CustomLighting i)
{
    half roughness = 1-(_Glossiness * i.metallicGlossMap.a);
    roughness *= 1.7 - 0.7 * roughness;
    half metallic = lerp(0, i.metallicGlossMap.r * _Metallic, 1);
    return half4(metallic, 0, 0, roughness);
}

half4 calcRimLight(CustomLighting i, DotProducts d, half4 lightCol, half3 indirectDiffuse, half3 envMap)
{  
    half rimIntensity = saturate((1-d.svdn)) * pow(d.ndl, 0.1);
    rimIntensity = smoothstep(_RimRange - 0.1, _RimRange + 0.1, rimIntensity);
    half4 rim = rimIntensity * _RimIntensity * (lightCol + indirectDiffuse.xyzz);
    rim *= i.attenuation + indirectDiffuse.xyzz;
    return rim * _RimColor * i.diffuseColor.rgbb* envMap.rgbb;
}

half3 calcDirectSpecular(CustomLighting i, DotProducts d, half4 lightCol, half3 indirectDiffuse, half4 metallicSmoothness)
{
    half specularIntensity = _SpecularIntensity * i.specularMap.r;
    half3 specular = half3(0,0,0);
    half smoothness = max(0.01, (_SpecularArea * i.specularMap.b));
    smoothness *= 1.7 - 0.7 * smoothness;
    
        half reflectionUntouched = saturate(pow(d.rdv, smoothness * 128));
        specular = lerp(reflectionUntouched, round(reflectionUntouched), 1) * specularIntensity * (_SpecularArea + 0.5);
    
    specular *= i.attenuation * lightCol;
    half3 tintedAlbedoSpecular = specular * i.diffuseColor;
    specular = lerp(specular, tintedAlbedoSpecular, i.specularMap.g); 
    return specular;
}


half3 calcIndirectSpecular(CustomLighting i, DotProducts d, half4 metallicSmoothness, half3 reflDir, half3 indirectLight, half3 viewDir)
{
        half3 spec = half3(0,0,0);

            #if defined(UNITY_PASS_FORWARDBASE) //Indirect PBR specular should only happen in the forward base pass. Otherwise each extra light adds another indirect sample, which could mean you're getting too much light. 
                half3 reflectionUV1 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
                half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS);
                half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR);

                half3 indirectSpecular;
                half interpolator = unity_SpecCube0_BoxMin.w;
                
                UNITY_BRANCH
                if (interpolator < 0.99999) 
                {
                    half3 reflectionUV2 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
                    half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS);
                    half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR);
                    indirectSpecular = lerp(probe1sample, probe0sample, interpolator);
                }
                else 
                {
                    indirectSpecular = probe0sample;
                }

                if (!any(indirectSpecular))
                {
                    indirectSpecular = texCUBElod(_BakedCubemap, half4(reflDir, metallicSmoothness.w * UNITY_SPECCUBE_LOD_STEPS));
                    indirectSpecular *= indirectLight;
                }

                half3 metallicColor = indirectSpecular * lerp(0.05,i.diffuseColor.rgb, metallicSmoothness.x);
                spec = lerp(indirectSpecular, metallicColor, pow(d.vdn, 0.05));
            #endif
    return spec;
}

half4 calcOutlineColor(CustomLighting i, DotProducts d, half3 indirectDiffuse, half4 lightCol)
{
    half3 outlineColor = half3(0,0,0);
    #if defined(Geometry)
        half3 ol = lerp(_OutlineColor, _OutlineColor * i.diffuseColor, 1);
        outlineColor = ol * saturate(i.attenuation * d.ndl) * lightCol.rgb;
        outlineColor += indirectDiffuse * ol;
    #endif
    return half4(outlineColor,1);
}

half3 calcIndirectDiffuse(CustomLighting i)
{
    half3 indirectDiffuse = ShadeSH9(float4(0,0.5,0,1));
    return indirectDiffuse;
}

half4 calcDiffuse(CustomLighting i, DotProducts d, half3 indirectDiffuse, half4 lightCol) 
{
    half4 diffuse; 
    half4 indirect = indirectDiffuse.xyzz;
    diffuse =  i.attenuation * lightCol + indirect;
    diffuse = i.albedo * diffuse;
    return diffuse;
}

half4 calcEmission(CustomLighting i, half lightAvg)
{
    #if defined(UNITY_PASS_FORWARDBASE) // Emission only in Base Pass, and vertex lights
        half4 emission =  i.emissionMap * i.diffuseColor.xyzz;
        half4 scaledEmission = emission * saturate(smoothstep(0, 2, 1-lightAvg));
        return lerp(scaledEmission, emission, 0);
    #else 
        return 0;
    #endif
}

void calcReflectionBlending(CustomLighting i, inout half4 col, half3 indirectSpecular)
{
        col += indirectSpecular.xyzz ;
}

//Lighting
half4 BRDF_CustomLighting(CustomLighting i)
{
    float3 untouchedNormal = i.normal;
    calcNormal(i);
    
    half4 vertexLightAtten = half4(0,0,0,0); 
    #if defined(VERTEXLIGHT_ON)
        half3 indirectDiffuse = calcIndirectDiffuse(i) + get4VertexLightsColFalloff(i.worldPos, i.normal, vertexLightAtten);   
    #else
        half3 indirectDiffuse = calcIndirectDiffuse(i);
    #endif

    bool lightEnv = any(_WorldSpaceLightPos0.xyz);
    half3 lightDir = calcLightDir(i, vertexLightAtten);
    half3 viewDir = calcViewDir(i.worldPos);
    half3 stereoViewDir = calcStereoViewDir(i.worldPos);
    half4 metallicSmoothness = calcMetallicSmoothness(i);
    half3 halfVector = normalize(lightDir + viewDir);
    half3 reflView = calcReflView(viewDir, i.normal);
    half3 reflLight = calcReflLight(lightDir, i.normal);
    
    DotProducts d = (DotProducts)0;
    d.ndl = dot(i.normal, lightDir);
    d.vdn = abs(dot(viewDir, i.normal));
    d.vdh = DotClamped(viewDir, halfVector);
    d.tdh = dot(i.tangent, halfVector);
    d.bdh = dot(i.bitangent, halfVector);
    d.ndh = DotClamped(i.normal, halfVector);
    d.rdv = saturate(dot(reflLight, float4(-viewDir, 0)));
    d.ldh = DotClamped(lightDir, halfVector);
    d.svdn = abs(dot(stereoViewDir, i.normal));
    
    i.albedo.rgb *= (1-metallicSmoothness.x);

    half4 lightCol = half4(0,0,0,0);
    calcLightCol(lightEnv, indirectDiffuse, lightCol);

    half lightAvg = (indirectDiffuse.r + indirectDiffuse.g + indirectDiffuse.b + lightCol.r + lightCol.g + lightCol.b) / 6;
    half3 envMapBlurred = getEnvMap(i, d, 5, reflView, indirectDiffuse, i.normal);

    half4 diffuse = calcDiffuse(i, d, indirectDiffuse, lightCol);
    half4 rimLight = calcRimLight(i, d, lightCol, indirectDiffuse, envMapBlurred);
    half3 indirectSpecular = calcIndirectSpecular(i, d, metallicSmoothness, reflView, indirectDiffuse, viewDir);
    half3 directSpecular = calcDirectSpecular(i, d, lightCol, indirectDiffuse, metallicSmoothness);
    half4 occlusion = lerp(_OcclusionColor, 1, i.occlusion.r);
    half4 outlineColor = calcOutlineColor(i, d, indirectDiffuse, lightCol);

    half stipplingDirect = 0;
    half stipplingRim = 0;
    half stipplingIndirect = 0;
    
    half4 col;
    col = diffuse ;
    calcReflectionBlending(i, col, indirectSpecular.xyzz);
    col += max(directSpecular.xyzz, rimLight);
    col *= occlusion;
    col += calcEmission(i, lightAvg);

    float4 finalColor = lerp(col, outlineColor, i.isOutline) ;
    return finalColor;
}

//Vertex
VertexOutput vert (VertexInput v)
{
    VertexOutput o = (VertexOutput)0;
    #if defined(Geometry)
        o.vertex = v.vertex;
    #endif

    o.pos = UnityObjectToClipPos(v.vertex);
    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    float3 wnormal = UnityObjectToWorldNormal(v.normal);
    float3 tangent = UnityObjectToWorldDir(v.tangent.xyz);
    half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
    float3 bitangent = cross(wnormal, tangent) * tangentSign;
    o.ntb[0] = wnormal;
    o.ntb[1] = tangent;
    o.ntb[2] = bitangent;
    o.uv = v.uv;
    o.color = float4(v.color.rgb, 0); 
    o.normal = v.normal;
    o.screenPos = ComputeScreenPos(o.pos);
    o.objPos = normalize(v.vertex);
    UNITY_TRANSFER_SHADOW(o, o.uv);
    UNITY_TRANSFER_FOG(o, o.pos);
    return o;
}

//Geometry
#if defined(Geometry)
    [maxvertexcount(6)]
    void geom(triangle v2g IN[3], inout TriangleStream<g2f> tristream)
    {
        g2f o;

        //Main Mesh loop
        for (int j = 0; j < 3; j++)
        {
            o.pos = UnityObjectToClipPos(IN[j].vertex);
            o.worldPos = IN[j].worldPos;
            o.ntb[0] = IN[j].ntb[0];
            o.ntb[1] = IN[j].ntb[1];
            o.ntb[2] = IN[j].ntb[2];
            o.uv = IN[j].uv;
            o.color = float4(IN[j].color.rgb,0); 
            o.screenPos = ComputeScreenPos(o.pos);
            o.objPos = normalize(IN[j].vertex);

            #if defined (SHADOWS_SCREEN) || ( defined (SHADOWS_DEPTH) && defined (SPOT) ) || defined (SHADOWS_CUBE)
                o._ShadowCoord = IN[j]._ShadowCoord; 
            #endif
            UNITY_TRANSFER_FOG(o, o.pos);
            tristream.Append(o);
        }
        tristream.RestartStrip();

        //Outlines loop
        for (int i = 2; i >= 0; i--)
        {	
            float4 worldPos = (mul(unity_ObjectToWorld, IN[i].vertex));
            float3 outlineWidth = _OutlineWidth * .01;
            outlineWidth *= min(distance(worldPos, _WorldSpaceCameraPos) * 3, 1);
            float4 outlinePos = float4(IN[i].vertex + normalize(IN[i].normal) * outlineWidth, 1);
            
                o.pos = UnityObjectToClipPos(outlinePos);

            o.worldPos = worldPos;
            o.ntb[0] = IN[i].ntb[0];
            o.ntb[1] = IN[i].ntb[1];
            o.ntb[2] = IN[i].ntb[2];
            o.uv = IN[i].uv;
            o.color = float4(_OutlineColor.rgb, 1); 
            o.screenPos = ComputeScreenPos(o.pos);
            o.objPos = normalize(outlinePos);

            #if defined (SHADOWS_SCREEN) || ( defined (SHADOWS_DEPTH) && defined (SPOT) ) || defined (SHADOWS_CUBE)
                o._ShadowCoord = IN[i]._ShadowCoord; 
            #endif
            UNITY_TRANSFER_FOG(o, o.pos);
            tristream.Append(o);
        }
        tristream.RestartStrip();
        

    }
#endif

//Frag
float4 frag (
    #if defined(Geometry)
        g2f i
    #else
        VertexOutput i
    #endif
    , uint facing : SV_IsFrontFace
    ) : SV_Target
{
    UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos.xyz);
	
	//修正了场景中没有方向光时灯光为0的罕见错误
	#ifdef UNITY_PASS_FORWARDBASE
		if(all(_LightColor0.rgb == 0.0))
		{
			attenuation = 1.0;
		}
	#endif
	
    #if defined(DIRECTIONAL)
        attenuation = lerp(attenuation, round(attenuation), _ShadowSharpness);
    #endif
    
    bool face = facing > 0;

    if (!face) 
    { 
        if(i.color.a > 0.99) { discard; }

        i.ntb[0] = -i.ntb[0];
        i.ntb[1] = -i.ntb[1];
        i.ntb[2] = -i.ntb[2];
    }

    TextureUV t = (TextureUV)0; // 填充uv

        InitializeTextureUVs(i, t);
   
    CustomLighting o = (CustomLighting)0; //填充照明结构
    
    o.albedo = UNITY_SAMPLE_TEX2D(_MainTex, t.albedoUV) * _Color;
    o.specularMap = UNITY_SAMPLE_TEX2D_SAMPLER(_SpecularMap, _MainTex, t.specularMapUV);
    o.metallicGlossMap = UNITY_SAMPLE_TEX2D_SAMPLER(_MetallicGlossMap, _MainTex, t.metallicGlossMapUV);
    o.normalMap = UNITY_SAMPLE_TEX2D_SAMPLER(_BumpMap, _MainTex, t.normalMapUV);
    o.occlusion = tex2D(_OcclusionMap, t.occlusionUV);
    o.emissionMap = UNITY_SAMPLE_TEX2D_SAMPLER(_EmissionMap, _MainTex, t.emissionMapUV) * _EmissionColor;

    o.diffuseColor = o.albedo.rgb; 
    o.attenuation = attenuation;
    o.normal = i.ntb[0];
    o.tangent = i.ntb[1];
    o.bitangent = i.ntb[2];
    o.worldPos = i.worldPos;
    o.color = i.color.rgb;
    o.isOutline = i.color.a;
    o.screenUV = calcScreenUVs(i.screenPos);
    o.objPos = i.objPos;

    float4 col = BRDF_CustomLighting(o);
    UNITY_APPLY_FOG(i.fogCoord, col);
    return float4(col.rgb, 1);
}